package ru.troyanov.Datchick.controllers;

import jakarta.validation.Valid;
import org.modelmapper.ModelMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import ru.troyanov.Datchick.dto.MeasurementDTO;
import ru.troyanov.Datchick.models.Measurement;
import ru.troyanov.Datchick.models.Sensor;
import ru.troyanov.Datchick.services.MeasurementService;
import ru.troyanov.Datchick.services.SensorsService;
import ru.troyanov.Datchick.util.MeasurementErrorResponse;
import ru.troyanov.Datchick.util.MeasurementNotCreatedException;
import ru.troyanov.Datchick.util.SensorValidatorForMeasurement;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/measurement")
public class MeasurementController {
    private final MeasurementService measurementService;
    private final ModelMapper modelMapper;
    private final SensorValidatorForMeasurement sensorValidatorForMeasurement;
    private final SensorsService sensorsService;

    public MeasurementController(MeasurementService measurementService, ModelMapper modelMapper, SensorValidatorForMeasurement sensorValidatorForMeasurement, SensorsService sensorsService) {
        this.measurementService = measurementService;
        this.modelMapper = modelMapper;
        this.sensorValidatorForMeasurement = sensorValidatorForMeasurement;
        this.sensorsService = sensorsService;
    }

    @GetMapping
    public List<MeasurementDTO> findAll() {
        return measurementService.findAll().stream().map(this::convertToMeasurementDTO).collect(Collectors.toList());
    }

    @GetMapping("/rainyDays")
    public List<MeasurementDTO> findRainyDays() {
        return measurementService.findRainyDay(true).stream().map(this::convertToMeasurementDTO).collect(Collectors.toList());
    }

    @PostMapping("/add")
    public ResponseEntity<HttpStatus> createMeasurement(@RequestBody @Valid MeasurementDTO measurementDTO, BindingResult bindingResult) {

        sensorValidatorForMeasurement.validate(measurementDTO, bindingResult);

        if (bindingResult.hasErrors()) {
            StringBuilder response = new StringBuilder();
            List<FieldError> errors = bindingResult.getFieldErrors();

            for (FieldError error : errors) {
                response.append(error.getField()).append(" - ").append(error.getDefaultMessage()).append(";");
            }

            throw new MeasurementNotCreatedException(response.toString());
        }
        measurementService.save(convertToMeasurement(measurementDTO));

        return new ResponseEntity<>(HttpStatus.OK);
    }

    @ExceptionHandler
    private ResponseEntity<MeasurementErrorResponse> handleException(MeasurementNotCreatedException e) {
        MeasurementErrorResponse measurementErrorResponse = new MeasurementErrorResponse(e.getMessage(), new Date());

        return new ResponseEntity<>(measurementErrorResponse, HttpStatus.BAD_REQUEST);
    }

    private MeasurementDTO convertToMeasurementDTO(Measurement measurement) {
        return modelMapper.map(measurement, MeasurementDTO.class);
    }

    private Measurement convertToMeasurement(MeasurementDTO measurementDTO) {
        Measurement measurement = modelMapper.map(measurementDTO, Measurement.class);
        Sensor sensor = sensorsService.findByName(measurementDTO.getSensorName()).get();
        measurement.setSensor(sensor);
        return measurement;
    }
}
